/** * GloboEvent Combined Search — complete clean version * Shared frontend controller for events + activities. * * Features: * - Combined search for events + activities * - Quiet language switching with ge_set_language + ge_get_ui_dict * - Audience remains client-side/local only * - Return-to-results restore for combined pages * - Restores exact clicked card when returning from single event page * - Normalizes saved-search payloads before restore * - Save search with prompt naming * - Saved search list with radio, share, share selected, delete selected, delete all * - Guest saved searches in localStorage * - Cards are NOT clickable; only the link/button opens the single page * - Search for events / Search for activities buttons scroll back to the search box * - Refresh/reload clears previous live search state */ jQuery(document).ready(function ($) { function isCombinedPage() { const $wrapper = $("#globoevent-wrapper"); if (!$wrapper.length) return false; const mode = String($wrapper.data("searchMode") || $wrapper.data("search-mode") || "").toLowerCase(); return mode === "combined"; } if (!isCombinedPage()) return; function geAjaxUrl() { if (window.GloboEvent && window.GloboEvent.ajax_url) return window.GloboEvent.ajax_url; if (window.ajaxurl) return window.ajaxurl; return "/wp-admin/admin-ajax.php"; } window.GloboEvent = window.GloboEvent || {}; if (!window.GloboEvent.ajax_url) window.GloboEvent.ajax_url = geAjaxUrl(); function geNormalizeLang(raw) { if (!raw) return "en"; raw = String(raw).trim().replace(/_/g, "-"); const low = raw.toLowerCase(); if (low === "fil" || low === "tl" || low === "fil-ph" || low === "tl-ph") return "fil"; if (low === "pt-br") return "pt-BR"; if (low === "zh-tw") return "zh-TW"; if (low === "fr-ca") return "fr-CA"; if (low === "no" || low.startsWith("no-")) return "nb"; if (low.startsWith("nb")) return "nb"; if (low.startsWith("nn")) return "nn"; if (low.includes("-")) { const parts = low.split("-"); const base = (parts[0] || "").toLowerCase(); const region = (parts[1] || "").toUpperCase(); if (base === "en") return region ? `${base}-${region}` : "en"; if (base === "pt" && region === "BR") return "pt-BR"; if (base === "zh" && region === "TW") return "zh-TW"; if (base === "fr" && region === "CA") return "fr-CA"; if (base === "fil" || base === "tl") return "fil"; return base || "en"; } if (low.length === 2) { if (low === "tl") return "fil"; return low; } return "en"; } window.geNormalizeLang = geNormalizeLang; function geLangPersistGet() { try { return localStorage.getItem("ge_lang_runtime") || ""; } catch (e) { return ""; } } function geLangPersistSet(lang) { try { localStorage.setItem("ge_lang_runtime", String(lang || "")); } catch (e) {} } function geGetLangCookie() { const m = document.cookie.match(/(^| )ge_lang=([^;]+)/); return m && m[2] ? decodeURIComponent(m[2]) : ""; } function getCurrentLang() { if (window.GE_LANG) return geNormalizeLang(window.GE_LANG); const persisted = geLangPersistGet(); if (persisted) return geNormalizeLang(persisted); const cookieRaw = geGetLangCookie(); if (cookieRaw) return geNormalizeLang(cookieRaw); const wrapperLang = $("#globoevent-wrapper").data("lang"); if (wrapperLang) return geNormalizeLang(wrapperLang); const htmlLang = document.documentElement.getAttribute("lang"); if (htmlLang) return geNormalizeLang(htmlLang); return "en"; } function geSetLangRuntime(lang) { lang = geNormalizeLang(lang || "en"); window.GE_LANG = lang; geLangPersistSet(lang); try { document.cookie = "ge_lang=" + encodeURIComponent(lang) + "; path=/; max-age=31536000; SameSite=Lax"; } catch (e) {} $("#globoevent-wrapper").attr("data-lang", lang).data("lang", lang); const $sel = $("#ge-language-select, .ge-language-select"); if ($sel.length && $sel.val() !== lang) $sel.val(lang); return lang; } function geEnsureLanguage() { const persisted = geLangPersistGet(); if (persisted) return geSetLangRuntime(persisted); const cookieRaw = geGetLangCookie(); if (cookieRaw) return geSetLangRuntime(cookieRaw); const wrapperLang = $("#globoevent-wrapper").data("lang"); if (wrapperLang) return geSetLangRuntime(wrapperLang); const browser = navigator.language || navigator.userLanguage || "en"; return geSetLangRuntime(browser); } window.GE_UI = window.GE_UI || {}; window.GE_AUDIENCE_DICT = window.GE_AUDIENCE_DICT || {}; function geApplyUiDict(ui) { if (!ui) ui = {}; window.GE_UI = Object.assign(window.GE_UI || {}, ui); if (ui.keyword) $("#ge-keyword").attr("placeholder", ui.keyword); if (ui.city) $("#ge-city").attr("placeholder", ui.city); if (ui.zip) $("#ge-zip").attr("placeholder", ui.zip); if (ui.country) $("#ge-country option:first").text(ui.country); if (ui.dates) $("#ge-date-btn").text(ui.dates); if (ui.search) $("#ge-search-btn").text(ui.search); if (ui.reset_all) $("#ge-reset-all").text(ui.reset_all); if (!ui.reset_all && ui.reset) $("#ge-reset-all").text(ui.reset); if (ui.advanced) $("#ge-advanced-btn").text(ui.advanced); if (!ui.advanced && ui.advanced_search) $("#ge-advanced-btn").text(ui.advanced_search); if (ui.save_search) $(".ge-save-search").text(ui.save_search); if (ui.saved_searches) $(".ge-saved-search").text(ui.saved_searches); if (!ui.saved_searches && ui.view_saved) $(".ge-saved-search").text(ui.view_saved); if (ui.today) $(".ge-today").text(ui.today); if (ui.weekend) $(".ge-weekend").text(ui.weekend); if (ui.nearby) $(".ge-nearby").text(ui.nearby); if (!ui.nearby && ui.my_location) $(".ge-nearby").text(ui.my_location); if (ui.filters) { $(".ge-mobile-filters-toggle, .ge-search-filters-toggle, #ge-search-filters-toggle").text(ui.filters); } } function geApplyAudienceDict(audDict) { if (!audDict) audDict = {}; window.GE_AUDIENCE_DICT = audDict; $(".ge-audience-checkbox").each(function () { const slug = String($(this).val() || "").trim(); if (!slug) return; const labelText = audDict[slug]; if (!labelText) return; const $label = $(this).closest("label"); if (!$label.length) return; const $span = $label.find("span").first(); if ($span.length) { $span.text(labelText); return; } const $lbl = $label.find(".ge-audience-label").first(); if ($lbl.length) { $lbl.text(labelText); return; } const $input = $(this); $label.contents().filter(function () { return this.nodeType === 3; }).remove(); $input.after(document.createTextNode(" " + labelText)); }); } function geLoadUiDict(lang, cb) { lang = geNormalizeLang(lang || "en"); $.post(geAjaxUrl(), { action: "ge_get_ui_dict", lang: lang, v: Date.now() }) .done(function (res) { if (res && res.success && res.data) { const ui = (res.data.ui && typeof res.data.ui === "object") ? res.data.ui : (res.data.dict && res.data.dict.ui && typeof res.data.dict.ui === "object") ? res.data.dict.ui : {}; const audience = (res.data.audience && typeof res.data.audience === "object") ? res.data.audience : (res.data.dict && res.data.dict.audience && typeof res.data.dict.audience === "object") ? res.data.dict.audience : {}; geApplyUiDict(ui); geApplyAudienceDict(audience); } if (typeof cb === "function") cb(res); }) .fail(function () { if (typeof cb === "function") cb(null); }); } function geGetUiText(key, fallback) { try { if (window.GE_UI && window.GE_UI[key]) return String(window.GE_UI[key]); } catch (e) {} return String(fallback || ""); } function esc(value) { return $("
").text(String(value || "")).html(); } function strip(value) { return $("
").html(String(value || "")).text().replace(/\s+/g, " ").trim(); } function geFormatEventDateTime(dateValue, timeValue) { const rawDate = strip(dateValue || ""); const rawTime = strip(timeValue || ""); if (!rawDate) { return { date: "", time: rawTime }; } const looksMachineDate = /\d{4}-\d{2}-\d{2}(?:[T\s]\d{2}:\d{2})?/.test(rawDate); const parsed = new Date(rawDate); if (looksMachineDate && !Number.isNaN(parsed.getTime())) { return { date: parsed.toLocaleDateString(undefined, { year: "numeric", month: "short", day: "numeric" }), time: rawTime || parsed.toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit" }) }; } return { date: rawDate, time: rawTime }; } function geEventDateMetaHtml(dateValue, timeValue) { const parts = geFormatEventDateTime(dateValue, timeValue); if (!parts.date && !parts.time) return ""; const dateHtml = parts.date ? `${esc(parts.date)}` : ""; const timeHtml = parts.time ? `${esc(parts.time)}` : ""; return `
${dateHtml}${timeHtml}
`; } function geCountryLabel(value) { const code = String(value || "").trim().toUpperCase(); const map = { NO: "Norway", SE: "Sweden", DK: "Denmark", FI: "Finland", IS: "Iceland", DE: "Germany", FR: "France", ES: "Spain", IT: "Italy", PT: "Portugal", NL: "Netherlands", BE: "Belgium", LU: "Luxembourg", GB: "United Kingdom", UK: "United Kingdom", IE: "Ireland", US: "United States", USA: "United States", CA: "Canada", AU: "Australia", NZ: "New Zealand", ZA: "South Africa", CH: "Switzerland", AT: "Austria", PL: "Poland", CZ: "Czech Republic", JP: "Japan", CN: "China", KR: "South Korea", IN: "India", BR: "Brazil", MX: "Mexico", CL: "Chile", AE: "United Arab Emirates", LV: "Latvia", BG: "Bulgaria", BU: "Myanmar", FO: "Faroe Islands", AR: "Argentina", CY: "Cyprus", LT: "Lithuania" }; return map[code] || String(value || "").trim(); } function forceHttpsUrl(url) { url = String(url || "").trim(); if (url.indexOf("http://") === 0) { return "https://" + url.substring(7); } return url; } function normalizeAudienceList(raw) { if (Array.isArray(raw)) { return raw.map(function (item) { if (typeof item === "string") return item.trim(); if (item && typeof item === "object") { if (item.slug) return String(item.slug).trim(); if (item.name) return String(item.name).trim(); } return ""; }).filter(Boolean); } if (typeof raw === "string") { return raw.split(",").map(function (item) { return String(item || "").trim(); }).filter(Boolean); } return []; } function geDedupeClean(value) { return String(value || "") .toLowerCase() .replace(/&/g, "&") .replace(/[^\p{L}\p{N}\s]+/gu, " ") .replace(/\s+/g, " ") .trim(); } function geDedupeKey(item, type) { const title = geDedupeClean(item.title || item.name || ""); const venue = geDedupeClean(item.venue_original || item.venue || item.location || ""); const city = geDedupeClean(item.city || ""); const country = geDedupeClean(item.country || ""); if (type === "events") { const date = geDedupeClean(item.date_display || item.start_date || ""); const time = geDedupeClean(item.time_display || item.time || ""); return [title, date, time, venue, city, country].join("|"); } return [title, venue, city, country].join("|"); } function geDedupeResults(items, type) { const list = Array.isArray(items) ? items : []; const seen = {}; const out = []; list.forEach(function (item) { const title = geDedupeClean(item.title || item.name || ""); if (!title) { out.push(item); return; } const key = geDedupeKey(item, type); if (seen[key]) return; seen[key] = true; out.push(item); }); return out; } const GE_SS_KEYS = { combined: "ge_combined_results_state" }; const GE_DISCOVERY_DISPLAY_SIZE = 4; const GE_DISCOVERY_POOL_SIZE = 12; const GE_MOBILE_DISCOVERY_POOL_SIZE = 8; const GE_IS_MOBILE = window.matchMedia && window.matchMedia("(max-width: 767px)").matches; const GE_EFFECTIVE_DISCOVERY_POOL_SIZE = GE_IS_MOBILE ? 8 : GE_DISCOVERY_POOL_SIZE; const state = { categoryId: 0, categorySlug: "", subcategory: [], audience: [], startDate: "", endDate: "", nearbyMode: false, nearbyStage: 0, activeTab: "events", hasSearched: false, page: { events: 1, activities: 1 }, loading: { events: false, activities: false }, pending: { events: null, activities: null }, limit: { events: 4, activities: 4 }, lastTotal: { events: 0, activities: 0 }, discovery: { events: { active: false, pool: [], visible: 0, sponsored: [], freshness: {} }, activities: { active: false, pool: [], visible: 0 } }, datePicker: null, requestSeq: 0 }; function syncAudienceFromUi() { state.audience = []; $(".ge-audience-checkbox:checked").each(function () { const val = String($(this).val() || "").trim(); if (val) state.audience.push(val); }); } function syncSubcategoriesFromUi() { state.subcategory = []; $(".ge-subcat-checkbox:checked").each(function () { const val = String($(this).val() || "").trim(); if (val) state.subcategory.push(val); }); } function parseDateInput() { const raw = String($("#ge-date-input").val() || "").trim(); if (!raw) { state.startDate = ""; state.endDate = ""; return; } const parts = raw.split(/\s+to\s+/i).map(function (s) { return String(s || "").trim(); }).filter(Boolean); state.startDate = parts[0] || ""; state.endDate = parts[1] || parts[0] || ""; } function geResetSearchUi() { $("#ge-keyword, #ge-city, #ge-zip, #ge-date-input").val(""); $("#ge-country").val(""); $(".ge-audience-checkbox, .ge-subcat-checkbox").prop("checked", false); $(".ge-cat-btn").removeClass("active"); $(".ge-subcategory-group").attr("hidden", true); state.categoryId = 0; state.categorySlug = ""; state.subcategory = []; state.audience = []; state.startDate = ""; state.endDate = ""; state.nearbyMode = false; state.nearbyStage = 0; state.hasSearched = false; state.page.events = 1; state.page.activities = 1; state.lastTotal.events = 0; state.lastTotal.activities = 0; state.discovery.events = { active: false, pool: [], visible: 0, sponsored: [], freshness: {}}; state.discovery.activities = { active: false, pool: [], visible: 0 }; } function getBaseQuery() { syncAudienceFromUi(); syncSubcategoriesFromUi(); parseDateInput(); return { keyword: String($("#ge-keyword").val() || "").trim(), city: String($("#ge-city").val() || "").trim(), country: String($("#ge-country").val() || "").trim(), zip: String($("#ge-zip").val() || "").trim(), category_slug: state.categorySlug || "", category: state.categoryId || 0, subcategory: state.subcategory.join(","), audience: state.audience.join(","), start_date: state.startDate || "", end_date: state.endDate || "" }; } function getScopedQuery() { const q = getBaseQuery(); if (!state.nearbyMode) return q; const scoped = { city: q.city, country: q.country, zip: q.zip }; if (state.nearbyStage >= 1) { scoped.city = ""; scoped.zip = ""; } if (state.nearbyStage >= 2) { scoped.country = ""; } return Object.assign({}, q, scoped); } function geSaveCombinedResultsState(targetMeta) { try { targetMeta = targetMeta || {}; const payload = { lang: getCurrentLang(), state: { categoryId: state.categoryId, categorySlug: state.categorySlug, subcategory: state.subcategory || [], audience: state.audience || [], startDate: state.startDate || "", endDate: state.endDate || "", nearbyMode: !!state.nearbyMode, nearbyStage: state.nearbyStage || 0, activeTab: state.activeTab || "events", hasSearched: !!state.hasSearched, page: state.page || { events: 1, activities: 1 }, lastTotal: state.lastTotal || { events: 0, activities: 0 } }, fields: { keyword: $("#ge-keyword").val() || "", city: $("#ge-city").val() || "", country: $("#ge-country").val() || "", zip: $("#ge-zip").val() || "", date_input: $("#ge-date-input").val() || "" }, html: { eventsCount: $("#ge-events-count").html() || "", activitiesCount: $("#ge-activities-count").html() || "", eventResults: $("#ge-event-results").html() || "", activityResults: $("#ge-activity-results").html() || "", eventPagination: $("#ge-event-pagination").html() || "", activityPagination: $("#ge-activity-pagination").html() || "" }, scrollTop: $(window).scrollTop() || 0, target: { id: String(targetMeta.id || "").trim(), url: String(targetMeta.url || "").trim() }, ts: Date.now() }; sessionStorage.setItem(GE_SS_KEYS.combined, JSON.stringify(payload)); } catch (e) {} } function geStripGeBackFromUrl() { try { const url = new URL(window.location.href); if (url.searchParams.has("ge_back")) { url.searchParams.delete("ge_back"); const clean = url.pathname + (url.searchParams.toString() ? "?" + url.searchParams.toString() : "") + url.hash; window.history.replaceState({}, document.title, clean); } } catch (e) {} } function geRestoreCombinedResultsState() { try { const raw = sessionStorage.getItem(GE_SS_KEYS.combined); if (!raw) return false; const saved = JSON.parse(raw); if (!saved || !saved.state || !saved.html) return false; if (saved.lang) geSetLangRuntime(saved.lang); $("#ge-keyword").val((saved.fields && saved.fields.keyword) || ""); $("#ge-city").val((saved.fields && saved.fields.city) || ""); $("#ge-country").val((saved.fields && saved.fields.country) || ""); $("#ge-zip").val((saved.fields && saved.fields.zip) || ""); $("#ge-date-input").val((saved.fields && saved.fields.date_input) || ""); state.categoryId = saved.state.categoryId || 0; state.categorySlug = saved.state.categorySlug || ""; state.subcategory = Array.isArray(saved.state.subcategory) ? saved.state.subcategory : []; state.audience = Array.isArray(saved.state.audience) ? saved.state.audience : []; state.startDate = saved.state.startDate || ""; state.endDate = saved.state.endDate || ""; state.nearbyMode = !!saved.state.nearbyMode; state.nearbyStage = parseInt(saved.state.nearbyStage || 0, 10); state.activeTab = saved.state.activeTab || "events"; state.hasSearched = !!saved.state.hasSearched; state.page = saved.state.page || { events: 1, activities: 1 }; state.lastTotal = saved.state.lastTotal || { events: 0, activities: 0 }; $(".ge-subcat-checkbox").prop("checked", false); state.subcategory.forEach(function (slug) { $(`.ge-subcat-checkbox[value="${slug}"]`).prop("checked", true); }); $(".ge-audience-checkbox").prop("checked", false); state.audience.forEach(function (slug) { $(`.ge-audience-checkbox[value="${slug}"]`).prop("checked", true); }); $(".ge-cat-btn").removeClass("active"); $(".ge-subcategory-group").attr("hidden", true); if (state.categoryId) { $(`.ge-cat-btn[data-cat-id="${state.categoryId}"], .ge-cat-btn[data-cat="${state.categoryId}"]`).addClass("active"); $(`.ge-subcategory-group[data-parent="${state.categoryId}"]`).removeAttr("hidden"); } $("#ge-events-count").html(saved.html.eventsCount || ""); $("#ge-activities-count").html(saved.html.activitiesCount || ""); $("#ge-event-results").html(saved.html.eventResults || ""); $("#ge-activity-results").html(saved.html.activityResults || ""); $("#ge-event-pagination").html(saved.html.eventPagination || ""); $("#ge-activity-pagination").html(saved.html.activityPagination || ""); setActiveTab(state.activeTab); applyUiLabels(); filterRenderedByAudience(); geApplyResultButtonsToDom(); const targetId = saved.target && saved.target.id ? String(saved.target.id).trim() : ""; const targetUrl = saved.target && saved.target.url ? String(saved.target.url).trim() : ""; const savedScrollTop = parseInt(saved.scrollTop || 0, 10) || 0; setTimeout(function () { let $target = $(); if (targetId) { $target = $("#ge-event-results .ge-event-card[data-id=\"" + targetId + "\"], #ge-activity-results .ge-event-card[data-id=\"" + targetId + "\"]").first(); } if ((!$target || !$target.length) && targetUrl) { $target = $(".ge-event-card a[href=\"" + targetUrl.replace(/"/g, '\\"') + "\"]").closest(".ge-event-card").first(); } if ($target && $target.length) { const top = Math.max($target.offset().top - 20, 0); $(window).scrollTop(top); } else { $(window).scrollTop(savedScrollTop); } }, 60); geStripGeBackFromUrl(); return true; } catch (e) { return false; } } function applySearchPayload(payload) { payload = payload || {}; if (payload && typeof payload === "object") { if (payload.search && typeof payload.search === "object") payload = payload.search; if (payload.filters && typeof payload.filters === "object") payload = payload.filters; } if (payload.lang) { const restoredLang = geNormalizeLang(payload.lang); geSetLangRuntime(restoredLang); const $sel = $("#ge-language-select, .ge-language-select"); if ($sel.length && $sel.val() !== restoredLang) $sel.val(restoredLang); } $("#ge-keyword").val(String(payload.keyword || "")); $("#ge-city").val(String(payload.city || "")); $("#ge-country").val(String(payload.country || "")); $("#ge-zip").val(String(payload.zip || "")); state.categorySlug = String(payload.category_slug || ""); state.categoryId = parseInt(payload.category || 0, 10) || 0; state.subcategory = String(payload.subcategory || "") .split(",") .map(function (v) { return String(v || "").trim(); }) .filter(Boolean); state.audience = String(payload.audience || "") .split(",") .map(function (v) { return String(v || "").trim(); }) .filter(Boolean); state.startDate = String(payload.start_date || payload.from || ""); state.endDate = String(payload.end_date || payload.to || ""); $("#ge-date-input").val( state.startDate && state.endDate && state.startDate !== state.endDate ? `${state.startDate} to ${state.endDate}` : (state.startDate || "") ); $(".ge-subcat-checkbox").prop("checked", false); state.subcategory.forEach(function (slug) { $(`.ge-subcat-checkbox[value="${slug}"]`).prop("checked", true); }); $(".ge-audience-checkbox").prop("checked", false); state.audience.forEach(function (slug) { $(`.ge-audience-checkbox[value="${slug}"]`).prop("checked", true); }); $(".ge-cat-btn").removeClass("active"); $(".ge-subcategory-group").attr("hidden", true); if (state.categoryId) { $(`.ge-cat-btn[data-cat-id="${state.categoryId}"], .ge-cat-btn[data-cat="${state.categoryId}"]`).addClass("active"); $(`.ge-subcategory-group[data-parent="${state.categoryId}"]`).removeAttr("hidden"); } } function isDiscoveryQuery(query) { query = query || {}; return !String(query.keyword || "").trim() && !String(query.city || "").trim() && !String(query.country || "").trim() && !String(query.zip || "").trim() && !String(query.category_slug || "").trim() && !parseInt(query.category || 0, 10) && !String(query.subcategory || "").trim() && !String(query.audience || "").trim() && !String(query.start_date || "").trim() && !String(query.end_date || "").trim(); } function discoveryEndHtml(type) { const label = type === "activities" ? geGetUiText("search_for_activities", "Search for activities") : geGetUiText("search_for_events", "Search for events"); return '
' + '' + '
'; } function renderNextDiscoveryEvents() { const bucket = state.discovery.events; const nextItems = bucket.pool.slice(bucket.visible, bucket.visible + GE_DISCOVERY_DISPLAY_SIZE); const append = bucket.visible > 0; if (!nextItems.length) { $("#ge-event-pagination").html(discoveryEndHtml("events")); geApplyResultButtonsToDom(); return; } bucket.visible += nextItems.length; const sponsoredHtml = (!append && bucket.sponsored.length) ? bucket.sponsored.map(function (ev) { return renderEventCard(ev, true); }).join("") : ""; const cardsHtml = nextItems.map(function (ev) { return renderEventCard(ev, false); }).join(""); if (append && $("#ge-event-results .ge-organic-grid").length) { $("#ge-event-results .ge-organic-grid").append(cardsHtml); } else { $("#ge-event-results").html( `
${sponsoredHtml}${cardsHtml}
` ); } const fresh = bucket.freshness || {}; const newLast24 = parseInt(fresh.new_last_24h || 0, 10); const updatedLast24 = parseInt(fresh.updated_last_24h || 0, 10); let freshHtml = ""; if (newLast24 > 0 || updatedLast24 > 0) { freshHtml = `
${esc(geGetUiText("updated_today", "Updated today"))} · ${newLast24} ${esc(geGetUiText("new_events", "new events"))} · ${updatedLast24} ${esc(geGetUiText("updated_events", "updated"))}
`; } $("#ge-events-count").html(`${state.lastTotal.events} ${esc(geGetUiText("upcoming_events_found", "upcoming events found"))}${freshHtml}`); $("#ge-event-pagination").html(bucket.visible < bucket.pool.length ? loadMoreHtml("events", false) : discoveryEndHtml("events")); if (!bucket.pool.length && !bucket.sponsored.length && !append) { $("#ge-event-results").html(`

${esc(geGetUiText("no_events_found", "No events found."))}

`); $("#ge-event-pagination").empty(); } filterRenderedByAudience(); geApplyResultButtonsToDom(); } function renderNextDiscoveryActivities() { const bucket = state.discovery.activities; const nextItems = bucket.pool.slice(bucket.visible, bucket.visible + GE_DISCOVERY_DISPLAY_SIZE); const append = bucket.visible > 0; if (!nextItems.length) { $("#ge-activity-pagination").html(discoveryEndHtml("activities")); geApplyResultButtonsToDom(); return; } bucket.visible += nextItems.length; const cardsHtml = nextItems.map(renderActivityCard).join(""); if (append && $("#ge-activity-results .ge-organic-grid").length) { $("#ge-activity-results .ge-organic-grid").append(cardsHtml); } else { $("#ge-activity-results").html(`
${cardsHtml}
`); } $("#ge-activities-count").text(`${state.lastTotal.activities} ${geGetUiText("activities_found", "activities found")}`); $("#ge-activity-pagination").html(bucket.visible < bucket.pool.length ? loadMoreHtml("activities", false) : discoveryEndHtml("activities")); if (!bucket.pool.length && !append) { $("#ge-activity-results").html(`

${esc(geGetUiText("no_activities_found", "No activities found."))}

`); $("#ge-activity-pagination").empty(); } filterRenderedByAudience(); geApplyResultButtonsToDom(); } function geIsBackIntent() { try { const sp = new URLSearchParams(window.location.search); if (sp.has("ge_back")) return true; } catch (e) {} return false; } function geApplyResultButtonsToDom() { const viewDetails = geGetUiText("view_details", "View details"); const viewTickets = geGetUiText("view_tickets", "View tickets"); const sponsored = geGetUiText("sponsored", "Sponsored"); const sponsoredHeading = geGetUiText("sponsored_events", "Sponsored events"); $("#ge-event-results .ge-event-btn:not(.ge-activity-ticket-btn)").text(viewDetails); $("#ge-activity-results .ge-event-btn:not(.ge-activity-ticket-btn)").text(viewDetails); $("#ge-activity-results .ge-activity-ticket-btn").text(viewTickets); $("#ge-event-results .ge-sponsored-badge").text(sponsored); $("#ge-event-results .ge-sponsored-heading").text(sponsoredHeading); const loadingMoreEvents = geGetUiText("loading_more_events", "Loading more events…"); const loadMoreEvents = geGetUiText("load_more_events", "Load more events"); const loadingMoreActivities = geGetUiText("loading_more_activities", "Loading more activities…"); const loadMoreActivities = geGetUiText("load_more_activities", "Load more activities"); const searchForEvents = geGetUiText("search_for_events", "Search for events"); const searchForActivities = geGetUiText("search_for_activities", "Search for activities"); $("#ge-event-pagination .ge-back-to-search-btn[data-type='events']").text(searchForEvents); $("#ge-activity-pagination .ge-back-to-search-btn[data-type='activities']").text(searchForActivities); $("#ge-event-pagination .ge-load-more-btn").each(function () { const $btn = $(this); const isBusy = $btn.is("[aria-busy='true']") || $btn.hasClass("is-loading"); $btn.find(".ge-load-more-label").text(isBusy ? loadingMoreEvents : loadMoreEvents); }); $("#ge-activity-pagination .ge-load-more-btn").each(function () { const $btn = $(this); const isBusy = $btn.is("[aria-busy='true']") || $btn.hasClass("is-loading"); $btn.find(".ge-load-more-label").text(isBusy ? loadingMoreActivities : loadMoreActivities); }); } function renderEventCard(ev, sponsored) { const safeTitle = strip(ev.title || ev.name || "Untitled event"); const safePermalink = String(ev.permalink || "#").trim() || "#"; const venueOriginal = strip(ev.venue_original || ev.venue || ev.location || ""); const safeCity = strip(ev.city || ""); const safeCountry = geCountryLabel(ev.country || ""); const locationParts = [venueOriginal, safeCity, safeCountry].filter(Boolean); const location = esc(locationParts.join(", ")); const dateMeta = geEventDateMetaHtml(ev.date_display || ev.start_date || "", ev.time_display || ev.time || ""); const imageUrl = forceHttpsUrl(ev.image || ev.image_url || ev.thumbnail || ""); const desc = strip(ev.description || ev.excerpt || ""); const description = desc ? `

${esc(desc)}

` : ""; const defaultEventImage = "https://globoevent.com/wp-content/uploads/2026/03/event_default_image.png"; const image = `${esc(safeTitle)}`; const sponsoredBadge = sponsored ? `
${esc(geGetUiText("sponsored", "Sponsored"))}
` : ""; const pastBadge = ( ev && ( ev.is_past === true || ev.is_past === 1 || ev.is_past === "1" || ev.status === "past" ) ) ? `
${esc(geGetUiText("past_event", "Past event"))}
` : ""; const audienceRaw = normalizeAudienceList(ev.audience || ev.audiences).join(","); return `
${image}
${sponsoredBadge} ${pastBadge}

${esc(safeTitle)}

${dateMeta}
📍 ${location}
${description}
`; } function renderActivityCard(ev) { const safeTitle = strip(ev.title || ev.name || "Untitled activity"); const safePermalink = String(ev.permalink || "#").trim() || "#"; const venueOriginal = strip(ev.venue_original || ev.venue || ev.location || ""); const safeCity = strip(ev.city || ""); const safeCountry = geCountryLabel(ev.country || ""); const locationParts = [venueOriginal, safeCity, safeCountry].filter(Boolean); const location = esc(locationParts.join(", ")); const imageUrl = forceHttpsUrl(ev.image || ev.image_url || ev.thumbnail || ""); const desc = strip(ev.description || ev.excerpt || ""); const description = desc ? `

${esc(desc)}

` : ""; const openingHours = strip(ev.opening_hours || ""); const activityKind = strip(ev.activity_kind || ""); const ticketUrl = forceHttpsUrl(ev.ticket_url || ev.cta_url || ""); const defaultActivityImage = "https://globoevent.com/wp-content/uploads/2026/04/find_activities_in_globoevent-scaled.jpg"; const image = `${esc(safeTitle)}`; const hoursHtml = openingHours ? `
🕒 ${esc(openingHours)}
` : ""; const kindHtml = activityKind ? `
🎡 ${esc(activityKind)}
` : ""; const detailsBtn = ` ${esc(geGetUiText("view_details", "View details"))} `; const ticketBtn = ticketUrl ? ` ${esc(geGetUiText("view_tickets", "View tickets"))} ` : ""; const audienceRaw = normalizeAudienceList(ev.audience || ev.audiences).join(","); return `
${image}

${esc(safeTitle)}

📍 ${location}
${kindHtml} ${hoursHtml} ${description}
${detailsBtn} ${ticketBtn}
`; } function sectionLoading(selector, message) { $(selector).html(`

${esc(message)}

`); } function sectionError(selector, message) { $(selector).html(`

${esc(message)}

`); } function loadMoreHtml(type, isLoading) { const isEvents = type === "events"; const loadLabel = isEvents ? (isLoading ? geGetUiText("loading_more_events", "Loading more events…") : geGetUiText("load_more_events", "Load more events")) : (isLoading ? geGetUiText("loading_more_activities", "Loading more activities…") : geGetUiText("load_more_activities", "Load more activities")); const searchLabel = isEvents ? geGetUiText("search_for_events", "Search for events") : geGetUiText("search_for_activities", "Search for activities"); const disabled = isLoading ? ' disabled aria-disabled="true" aria-busy="true"' : ""; const loadingClass = isLoading ? " is-loading" : ""; return '' + '
' + '' + '' + '
'; } function renderEventsSection(data, append) { const results = geDedupeResults(Array.isArray(data.results) ? data.results : [], "events"); const sponsored = geDedupeResults(Array.isArray(data.sponsored_results) ? data.sponsored_results : [], "events"); const total = parseInt(data.total || results.length || 0, 10); state.lastTotal.events = total; if (state.discovery.events.active && !append) { state.discovery.events.pool = results.slice(); state.discovery.events.visible = 0; state.discovery.events.sponsored = sponsored.slice(); state.discovery.events.freshness = data.freshness || {}; renderNextDiscoveryEvents(); return; } const sponsoredHtml = (sponsored.length && !append) ? sponsored.map(function (ev) { return renderEventCard(ev, true); }).join("") : ""; const cardsHtml = results.map(function (ev) { return renderEventCard(ev, false); }).join(""); if (append && $("#ge-event-results .ge-organic-grid").length) { const existingKeys = {}; $("#ge-event-results .ge-event-card").each(function () { const key = [ geDedupeClean($(this).find(".ge-event-title").text()), geDedupeClean($(this).find(".ge-event-meta").first().text().replace("📅", "")), geDedupeClean($(this).attr("data-venue-original") || ""), geDedupeClean($(this).find(".ge-event-meta").eq(1).text().replace("📍", "")) ].join("|"); existingKeys[key] = true; }); const freshHtml = results.filter(function (ev) { const key = [ geDedupeClean(ev.title || ev.name || ""), geDedupeClean((ev.date_display || ev.start_date || "") + " " + (ev.time_display || ev.time || "")), geDedupeClean(ev.venue_original || ev.venue || ev.location || ""), geDedupeClean([ev.city || "", ev.country || ""].filter(Boolean).join(" ")) ].join("|"); if (existingKeys[key]) return false; existingKeys[key] = true; return true; }).map(function (ev) { return renderEventCard(ev, false); }).join(""); $("#ge-event-results .ge-organic-grid").append(freshHtml); } else { $("#ge-event-results").html( `
${sponsoredHtml}${cardsHtml}
` ); } const fresh = data.freshness || {}; const newLast24 = parseInt(fresh.new_last_24h || 0, 10); const updatedLast24 = parseInt(fresh.updated_last_24h || 0, 10); let freshHtml = ""; if (newLast24 > 0 || updatedLast24 > 0) { freshHtml = `
${esc(geGetUiText("updated_today", "Updated today"))} · ${newLast24} ${esc(geGetUiText("new_events", "new events"))} · ${updatedLast24} ${esc(geGetUiText("updated_events", "updated"))}
`; } $("#ge-events-count").html(`${total} ${esc(geGetUiText("upcoming_events_found", "upcoming events found"))}${freshHtml}`); if (data.has_more) { $("#ge-event-pagination").html(loadMoreHtml("events", false)); } else if (state.hasSearched) { $("#ge-event-pagination").html( '
' + '' + '
' ); } else { $("#ge-event-pagination").empty(); } if (!results.length && !sponsored.length && !append) { $("#ge-event-results").html(`

${esc(geGetUiText("no_events_found", "No events found."))}

`); $("#ge-event-pagination").empty(); } filterRenderedByAudience(); geApplyResultButtonsToDom(); } function renderActivitiesSection(data, append) { const results = geDedupeResults(Array.isArray(data.results) ? data.results : [], "activities"); const total = parseInt(data.total || results.length || 0, 10); state.lastTotal.activities = total; if (state.discovery.activities.active && !append) { state.discovery.activities.pool = results.slice(); state.discovery.activities.visible = 0; renderNextDiscoveryActivities(); return; } const cardsHtml = results.map(renderActivityCard).join(""); if (append && $("#ge-activity-results .ge-organic-grid").length) { $("#ge-activity-results .ge-organic-grid").append(cardsHtml); } else { $("#ge-activity-results").html(`
${cardsHtml}
`); } $("#ge-activities-count").text(`${total} ${geGetUiText("activities_found", "activities found")}`); if (data.has_more) { $("#ge-activity-pagination").html(loadMoreHtml("activities", false)); } else if (state.hasSearched) { $("#ge-activity-pagination").html( '
' + '' + '
' ); } else { $("#ge-activity-pagination").empty(); } if (!results.length && !append) { $("#ge-activity-results").html(`

${esc(geGetUiText("no_activities_found", "No activities found."))}

`); $("#ge-activity-pagination").empty(); } filterRenderedByAudience(); geApplyResultButtonsToDom(); } function abortPending(type) { const req = state.pending[type]; if (req && typeof req.abort === "function") { try { req.abort("abort"); } catch (e) {} } state.pending[type] = null; } function eventsRequest(query, page) { abortPending("events"); state.loading.events = true; const eventCity = String(query.city || "").trim(); const eventZip = String(query.zip || "").trim(); // Important: if city or zip exists, do not also send country. // City + country meta queries are too slow on events. const eventCountry = (eventCity || eventZip) ? "" : String(query.country || "").trim(); const data = { action: "ge_search_events", lang: getCurrentLang(), keyword: query.keyword, category_slug: query.category_slug, category: query.category, subcategory: query.subcategory, audience: query.audience, start_date: query.start_date, end_date: query.end_date, page: isDiscoveryQuery(query) ? 1 : page, limit: isDiscoveryQuery(query) ? GE_EFFECTIVE_DISCOVERY_POOL_SIZE : state.limit.events }; if (eventCity) data.city = eventCity; if (eventZip) data.zip = eventZip; if (eventCountry) data.country = eventCountry; state.pending.events = $.ajax({ url: geAjaxUrl(), method: "POST", dataType: "json", timeout: 60000, data: data }).fail(function (jqXHR, textStatus, errorThrown) { console.error("ge_search_events failed", { textStatus: textStatus, errorThrown: errorThrown, status: jqXHR.status, responseText: jqXHR.responseText }); }); return state.pending.events.always(function () { state.loading.events = false; state.pending.events = null; }); } function activitiesRequest(query, page) { abortPending("activities"); state.loading.activities = true; state.pending.activities = $.ajax({ url: geAjaxUrl(), method: "POST", dataType: "json", timeout: 30000, data: { action: "ge_search_activities", lang: getCurrentLang(), keyword: query.keyword, city: query.city, country: query.country, zip: query.zip, category_slug: query.category_slug, category: query.category, subcategory: query.subcategory, audience: query.audience, page: isDiscoveryQuery(query) ? 1 : page, limit: isDiscoveryQuery(query) ? GE_EFFECTIVE_DISCOVERY_POOL_SIZE : state.limit.activities, preload: isDiscoveryQuery(query) ? 1 : 0 } }).fail(function (jqXHR, textStatus, errorThrown) { console.error("ge_search_activities failed", { textStatus: textStatus, errorThrown: errorThrown, status: jqXHR.status, responseText: jqXHR.responseText }); }); return state.pending.activities.always(function () { state.loading.activities = false; state.pending.activities = null; }); } function normalizeResponse(res) { if (typeof res === "string") { try { res = JSON.parse(res); } catch (e) { res = {}; } } return (res && res.data) ? res.data : {}; } function shouldFallback(eventsData, activitiesData, append) { if (!state.nearbyMode || append) return false; const eLen = Array.isArray(eventsData.results) ? eventsData.results.length : 0; const eSponsor = Array.isArray(eventsData.sponsored_results) ? eventsData.sponsored_results.length : 0; const aLen = Array.isArray(activitiesData.results) ? activitiesData.results.length : 0; return eLen === 0 && eSponsor === 0 && aLen === 0 && state.nearbyStage < 2; } function renderFallbackMessage() { if (state.nearbyStage === 1) { $("#ge-results").prepend(`
${esc(geGetUiText("no_local_results_expanding_country", "No local results. Expanding to your country…"))}
`); } else if (state.nearbyStage === 2) { $("#ge-results").prepend(`
${esc(geGetUiText("no_country_results_global", "No nearby country results. Showing global results…"))}
`); } } function setActiveTab(tab) { state.activeTab = (tab === "activities") ? "activities" : "events"; $(".ge-results-tab").removeClass("active").attr("aria-selected", "false"); $(`.ge-results-tab[data-tab="${state.activeTab}"]`).addClass("active").attr("aria-selected", "true"); $("#ge-events-section, #ge-activities-section").removeClass("is-active"); if (state.activeTab === "events") $("#ge-events-section").addClass("is-active"); else $("#ge-activities-section").addClass("is-active"); } function renderPreSearchState() { $("#ge-events-count").empty(); $("#ge-activities-count").empty(); $("#ge-event-pagination").empty(); $("#ge-activity-pagination").empty(); $("#ge-event-results").html( `
${esc(geGetUiText("presearch_events", "Search to find upcoming events."))}
` ); $("#ge-activity-results").html( `
${esc(geGetUiText("presearch_activities", "Search to find ongoing activities."))}
` ); setActiveTab(state.activeTab); geApplyResultButtonsToDom(); } function bindTabs() { $(document) .off("click.geResultsTabs", ".ge-results-tab") .on("click.geResultsTabs", ".ge-results-tab", function (e) { e.preventDefault(); setActiveTab(String($(this).data("tab") || "events")); }); } function filterRenderedByAudience() { const selected = Array.isArray(state.audience) ? state.audience : []; const applyFilter = function ($cards) { let visibleCount = 0; $cards.each(function () { const $card = $(this); const raw = String($card.attr("data-audience") || "").trim(); const itemAudiences = raw ? raw.split(",").map(function (v) { return String(v || "").trim(); }).filter(Boolean) : []; let show = true; if (selected.length) { show = selected.some(function (wanted) { return itemAudiences.includes(wanted); }); } $card.toggle(show); if (show) visibleCount += 1; }); return visibleCount; }; const visibleEvents = applyFilter($("#ge-event-results .ge-event-card")); const visibleActivities = applyFilter($("#ge-activity-results .ge-activity-card")); const fresh = state.discovery.events.freshness || {}; const newLast24 = parseInt(fresh.new_last_24h || 0, 10); const updatedLast24 = parseInt(fresh.updated_last_24h || 0, 10); let freshHtml = ""; if (newLast24 > 0 || updatedLast24 > 0) { freshHtml = `
${esc(geGetUiText("updated_today", "Updated today"))} · ${newLast24} ${esc(geGetUiText("new_events", "new events"))} · ${updatedLast24} ${esc(geGetUiText("updated_events", "updated"))}
`; } const eventCount = selected.length ? visibleEvents : state.lastTotal.events; $("#ge-events-count").html( `${eventCount} ${esc(geGetUiText("upcoming_events_found", "upcoming events found"))}${freshHtml}` ); $("#ge-activities-count").text( selected.length ? `${visibleActivities} ${geGetUiText("activities_found", "activities found")}` : `${state.lastTotal.activities} ${geGetUiText("activities_found", "activities found")}` ); } function applyUiLabels() { geApplyUiDict(window.GE_UI || {}); geApplyAudienceDict(window.GE_AUDIENCE_DICT || {}); $(".ge-mobile-filters-toggle, .ge-search-filters-toggle, #ge-search-filters-toggle") .text(geGetUiText("filters", "Search & Filters")); $("#ge-events-section .ge-results-section-title").text(geGetUiText("events", "Events")); $("#ge-activities-section .ge-results-section-title").text(geGetUiText("activities", "Activities")); $('.ge-results-tab[data-tab="events"]').text(geGetUiText("events", "Events")); $('.ge-results-tab[data-tab="activities"]').text(geGetUiText("activities", "Activities")); const $advancedHeadings = $("#ge-advanced-panel h4"); if ($advancedHeadings.length) $advancedHeadings.first().text(geGetUiText("audience", "Audience")); const $modalH3 = $("#ge-category-modal h3").first(); if ($modalH3.length) $modalH3.text(geGetUiText("refine_category", "Refine category")); const $modalH4 = $("#ge-category-modal h4").first(); if ($modalH4.length) $modalH4.text(geGetUiText("subcategories", "Subcategories")); geApplyResultButtonsToDom(); if (!state.hasSearched) renderPreSearchState(); else filterRenderedByAudience(); } function runCombinedSearch(options) { options = options || {}; state.hasSearched = true; const appendType = options.appendType || ""; const resetPages = !appendType; const requestId = ++state.requestSeq; if (resetPages) { state.page.events = 1; state.page.activities = 1; sectionLoading("#ge-event-results", geGetUiText("loading_events", "Loading events…")); sectionLoading("#ge-activity-results", geGetUiText("loading_activities", "Loading activities…")); $("#ge-event-pagination, #ge-activity-pagination").empty(); $(".ge-fallback-message").remove(); } const query = getScopedQuery(); const discoveryQuery = isDiscoveryQuery(query); if (resetPages) { state.discovery.events = { active: discoveryQuery, pool: [], visible: 0, sponsored: [], freshness: {} }; state.discovery.activities = { active: discoveryQuery, pool: [], visible: 0 }; } const wantEvents = appendType === "" || appendType === "events"; const wantActivities = appendType === "" || appendType === "activities"; const eventPromise = wantEvents ? eventsRequest(query, state.page.events) : $.Deferred().resolve({ data: { results: [], total: state.lastTotal.events, has_more: false } }).promise(); const activityPromise = wantActivities ? activitiesRequest(query, state.page.activities) : $.Deferred().resolve({ data: { results: [], total: state.lastTotal.activities, has_more: false } }).promise(); function safeSearchPromise(promise, type) { const d = $.Deferred(); promise .done(function (res) { d.resolve({ ok: true, type: type, res: res }); }) .fail(function (jqXHR, textStatus, errorThrown) { if (textStatus === "abort") { d.resolve({ ok: false, aborted: true, type: type }); return; } console.error("ge_search_" + type + " failed safely", { textStatus: textStatus, errorThrown: errorThrown, status: jqXHR && jqXHR.status, responseText: jqXHR && jqXHR.responseText }); d.resolve({ ok: false, type: type, jqXHR: jqXHR, textStatus: textStatus, errorThrown: errorThrown }); }); return d.promise(); } $.when(safeSearchPromise(eventPromise, "events"), safeSearchPromise(activityPromise, "activities")) .done(function (eventWrap, activityWrap) { if (requestId !== state.requestSeq) return; if ((eventWrap && eventWrap.aborted) || (activityWrap && activityWrap.aborted)) return; const eventsData = eventWrap && eventWrap.ok ? normalizeResponse(eventWrap.res) : { results: [], total: 0, has_more: false }; const activitiesData = activityWrap && activityWrap.ok ? normalizeResponse(activityWrap.res) : { results: [], total: 0, has_more: false }; if ((eventWrap && eventWrap.ok) && (activityWrap && activityWrap.ok) && shouldFallback(eventsData, activitiesData, !!appendType)) { state.nearbyStage += 1; renderFallbackMessage(); runCombinedSearch({ appendType: "" }); return; } if (wantEvents) { if (eventWrap && eventWrap.ok) renderEventsSection(eventsData, appendType === "events"); else sectionError("#ge-event-results", geGetUiText("events_failed_to_load", "Events failed to load.")); } if (wantActivities) { if (activityWrap && activityWrap.ok) renderActivitiesSection(activitiesData, appendType === "activities"); else sectionError("#ge-activity-results", geGetUiText("activities_failed_to_load", "Activities failed to load.")); } if (wantEvents && (!eventWrap || !eventWrap.ok)) $("#ge-events-count").text(""); if (wantActivities && (!activityWrap || !activityWrap.ok)) $("#ge-activities-count").text(""); setActiveTab(state.activeTab); geApplyResultButtonsToDom(); }); } function geLocalDateString(date) { const y = date.getFullYear(); const m = String(date.getMonth() + 1).padStart(2, "0"); const d = String(date.getDate()).padStart(2, "0"); return `${y}-${m}-${d}`; } function setToday() { const today = geLocalDateString(new Date()); state.startDate = today; state.endDate = today; $("#ge-date-input").val(today); } function setWeekend() { const now = new Date(); const day = now.getDay(); // 0 = Sunday, 6 = Saturday const saturday = new Date(now); const sunday = new Date(now); if (day === 6) { // Saturday: today + tomorrow sunday.setDate(now.getDate() + 1); } else if (day === 0) { // Sunday: yesterday + today saturday.setDate(now.getDate() - 1); } else { // Monday-Friday: upcoming Saturday/Sunday saturday.setDate(now.getDate() + (6 - day)); sunday.setDate(saturday.getDate() + 1); } state.startDate = geLocalDateString(saturday); state.endDate = geLocalDateString(sunday); $("#ge-date-input").val(`${state.startDate} to ${state.endDate}`); } function initDatePicker() { const $input = $("#ge-date-input"); const $btn = $("#ge-date-btn"); if (!$input.length || !$btn.length) return; if (typeof window.flatpickr === "function") { state.datePicker = window.flatpickr($input[0], { mode: "range", dateFormat: "Y-m-d", allowInput: false, clickOpens: false, onChange: function (dates, dateStr) { $input.val(dateStr || ""); parseDateInput(); if (dates.length === 2 || (dates.length === 1 && dateStr)) { state.nearbyMode = false; state.nearbyStage = 0; runCombinedSearch(); } } }); $(document).off("click.geDateBtn", "#ge-date-btn").on("click.geDateBtn", "#ge-date-btn", function (e) { e.preventDefault(); try { state.datePicker.open(); } catch (err) {} }); return; } $(document).off("click.geDateBtn", "#ge-date-btn").on("click.geDateBtn", "#ge-date-btn", function (e) { e.preventDefault(); const typed = window.prompt( geGetUiText("date_prompt", "Enter date or range as YYYY-MM-DD or YYYY-MM-DD to YYYY-MM-DD"), $("#ge-date-input").val() || "" ); if (typed === null) return; $("#ge-date-input").val(String(typed || "").trim()); parseDateInput(); state.nearbyMode = false; state.nearbyStage = 0; runCombinedSearch(); }); } $(document).on("click", ".ge-back-to-search-btn", function (e) { e.preventDefault(); const $target = $("#ge-search-form").length ? $("#ge-search-form") : $(".ge-filter-row").first().length ? $(".ge-filter-row").first() : $("#globoevent-wrapper").length ? $("#globoevent-wrapper") : $("body"); $("html, body").animate({ scrollTop: Math.max(($target.offset() ? $target.offset().top : 0) - 20, 0) }, 600); }); function geCleanNearbyCity(value) { return String(value || "") .replace(/\s+Municipality$/i, "") .replace(/\s+Commune$/i, "") .replace(/\s+County$/i, "") .trim(); } function bindNearby() { $(document) .off("click.geCombinedNearby", ".ge-nearby") .on("click.geCombinedNearby", ".ge-nearby", function (e) { e.preventDefault(); if (!navigator.geolocation) { alert("Geolocation not supported."); return; } navigator.geolocation.getCurrentPosition(function (position) { const lat = position.coords.latitude; const lng = position.coords.longitude; fetch(`https://nominatim.openstreetmap.org/reverse?format=json&zoom=10&addressdetails=1&lat=${encodeURIComponent(lat)}&lon=${encodeURIComponent(lng)}`) .then(function (res) { if (!res.ok) throw new Error("Reverse geocode failed"); return res.json(); }) .then(function (data) { const a = (data && data.address) ? data.address : {}; const rawCity = a.city || a.town || a.village || a.municipality || a.suburb || a.county || ""; const city = geCleanNearbyCity(rawCity); const country = a.country_code ? a.country_code.toUpperCase() : ""; $("#ge-city").val(city || ""); $("#ge-country").val(country || ""); $("#ge-zip").val(""); state.nearbyMode = true; state.nearbyStage = 0; runCombinedSearch(); }) .catch(function () { state.nearbyMode = true; state.nearbyStage = 0; $("#ge-city").val(""); $("#ge-country").val(""); $("#ge-zip").val(""); runCombinedSearch(); }); }, function () { alert("Location permission denied or unavailable."); }, { enableHighAccuracy: false, timeout: 15000, maximumAge: 60000 }); }); } function geEnsureSavedContainer() { if ($("#ge-saved-container").length) return; const html = '
'; if ($("#globoevent-wrapper").length) $("#globoevent-wrapper").prepend(html); else if ($("#ge-results").length) $("#ge-results").before(html); else $("body").prepend(html); } function geIsLoggedIn() { try { return document.body && (document.body.className || "").indexOf("logged-in") !== -1; } catch (e) {} return false; } function geGuestStoreKey() { const host = (location && location.host) ? location.host : "site"; return "ge_saved_searches_guest_" + host + "_combined"; } function geGuestLoadAll() { try { const raw = localStorage.getItem(geGuestStoreKey()); const arr = raw ? JSON.parse(raw) : []; return Array.isArray(arr) ? arr : []; } catch (e) { return []; } } function geGuestSaveAll(arr) { try { localStorage.setItem(geGuestStoreKey(), JSON.stringify(Array.isArray(arr) ? arr : [])); } catch (e) {} } function geGuestMakeFiltersPayload() { syncAudienceFromUi(); syncSubcategoriesFromUi(); parseDateInput(); return { keyword: $("#ge-keyword").val() || "", city: $("#ge-city").val() || "", zip: $("#ge-zip").val() || "", country: $("#ge-country").val() || "", lang: (typeof getCurrentLang === "function") ? getCurrentLang() : "en", audience: Array.isArray(state.audience) ? state.audience.join(",") : "", category: state.categoryId || 0, category_slug: state.categorySlug || "", subcategory: Array.isArray(state.subcategory) ? state.subcategory.join(",") : "", from: state.startDate || "", to: state.endDate || "", free_only: 0, tags: [] }; } function geServerSaysLoginRequired(res) { const msg = (res && res.data && (res.data.message || res.data.error)) ? String(res.data.message || res.data.error) : ""; return msg.toLowerCase().indexOf("login") !== -1; } function getSavedSearchesRequest() { return $.ajax({ url: geAjaxUrl(), method: "POST", dataType: "json", timeout: 30000, data: { action: "ge_load_saved_searches" } }); } function geShareIconSvg() { return ''; } function geBuildShareUrl(filters) { const data = filters || {}; const params = new URLSearchParams(); function setIf(key, val) { if (val === undefined || val === null) return; const str = String(val).trim(); if (!str || str === "0") return; params.set(key, str); } setIf("keyword", data.keyword || ""); setIf("city", data.city || ""); setIf("zip", data.zip || ""); setIf("country", data.country || ""); setIf("lang", data.lang || getCurrentLang()); setIf("audience", data.audience || ""); setIf("category", data.category || ""); setIf("subcategory", data.subcategory || ""); setIf("from", data.from || data.start_date || ""); setIf("to", data.to || data.end_date || ""); const url = new URL(window.location.href); url.search = params.toString(); return url.toString(); } function geOpenShareMenu(anchorEl, shareUrl, shareTitle) { $(".ge-share-menu").remove(); const title = shareTitle || "Check out this GloboEvent search"; const text = "I found this search on GloboEvent"; const encodedUrl = encodeURIComponent(shareUrl); const encodedText = encodeURIComponent(text + " " + shareUrl); const encodedTitle = encodeURIComponent(title); const menu = $( '' ); $("body").append(menu); const offset = $(anchorEl).offset() || { top: 0, left: 0 }; menu.css({ position: "absolute", top: offset.top + $(anchorEl).outerHeight() + 8, left: Math.max(12, offset.left - 120 + ($(anchorEl).outerWidth() || 0)), zIndex: 99999, minWidth: "180px", background: "#fff", border: "1px solid #ddd", borderRadius: "12px", boxShadow: "0 10px 30px rgba(0,0,0,0.12)", padding: "8px", display: "grid", gap: "6px" }); menu.find(".ge-share-option").css({ display: "block", width: "100%", border: "0", background: "#fff", color: "#111", textAlign: "left", padding: "10px 12px", borderRadius: "10px", textDecoration: "none", cursor: "pointer" }); menu.on("click", "[data-share-copy]", function (e) { e.preventDefault(); if (navigator.clipboard && navigator.clipboard.writeText) { navigator.clipboard.writeText(shareUrl).then(function () { alert(geGetUiText("link_copied", "Link copied.")); }, function () { window.prompt(geGetUiText("copy_this_link", "Copy this link:"), shareUrl); }); } else { window.prompt(geGetUiText("copy_this_link", "Copy this link:"), shareUrl); } menu.remove(); }); menu.on("click", "[data-share-email]", function (e) { e.preventDefault(); const subject = $(this).attr("data-share-title") || encodedTitle; const body = $(this).attr("data-share-body") || encodedText; window.location.href = "mailto:?subject=" + subject + "&body=" + body; menu.remove(); }); menu.on("click", "[data-share-native]", function (e) { e.preventDefault(); if (navigator.share) { navigator.share({ title: title, text: text, url: shareUrl }).catch(function () {}); } else { window.prompt(geGetUiText("copy_this_link", "Copy this link:"), shareUrl); } menu.remove(); }); setTimeout(function () { $(document).one("click.geShareMenu", function (ev) { if (!$(ev.target).closest(".ge-share-menu, .ge-saved-share, .ge-share-selected").length) { $(".ge-share-menu").remove(); } }); }, 0); } function renderSavedSearches(items) { const list = Array.isArray(items) ? items : []; if (!list.length) { $("#ge-saved-container").html( '
' + esc(geGetUiText("no_saved_searches", "No saved searches.")) + "
" ); return; } let html = '
'; list.forEach(function (item, index) { let payload = (item && item.filters) ? item.filters : ((item && item.search) ? item.search : item); if (typeof payload === "string") { try { payload = JSON.parse(payload); } catch (e) { payload = {}; } } if (payload && typeof payload === "object") { if (payload.search && typeof payload.search === "object") payload = payload.search; if (payload.filters && typeof payload.filters === "object") payload = payload.filters; } const label = (item && (item.name || item.label || item.title)) || (geGetUiText("saved_search", "Saved search") + " " + (index + 1)); html += `
`; }); html += `
`; html += "
"; $("#ge-saved-container").html(html); } $(document) .off("click.geSaveSearch touchend.geSaveSearch", ".ge-save-search") .on("click.geSaveSearch touchend.geSaveSearch", ".ge-save-search", function (e) { e.preventDefault(); const promptText = geGetUiText( "save_search_prompt", "Name this search:\n\nThis search is saved temporarily in your browser on this device. It may be removed if you clear browser data or cache." ); const rawName = window.prompt(promptText, ""); if (rawName === null) return; const name = String(rawName || "").trim(); if (!name) return; if (!geIsLoggedIn()) { const all = geGuestLoadAll(); all.unshift({ name: name, filters: geGuestMakeFiltersPayload(), ts: Date.now() }); geGuestSaveAll(all); $("#ge-saved-container").html( '
' + esc(geGetUiText("search_saved_device", "Search saved on this device.")) + "
" ); return; } const payload = geGuestMakeFiltersPayload(); $.ajax({ url: geAjaxUrl(), method: "POST", dataType: "json", timeout: 60000, data: { action: "ge_save_search", name: name, keyword: payload.keyword || "", city: payload.city || "", zip: payload.zip || "", country: payload.country || "", lang: payload.lang || getCurrentLang(), audience: payload.audience || "", category: payload.category || 0, subcategory: payload.subcategory || "", from: payload.from || "", to: payload.to || "", free_only: 0, tags: [] } }).done(function (res) { if (typeof res === "string") { try { res = JSON.parse(res); } catch (err) { res = {}; } } if (res && res.success) { $("#ge-saved-container").html( '
' + esc(geGetUiText("search_saved_device", "Search saved on this device.")) + "
" ); return; } if (geServerSaysLoginRequired(res)) { const all = geGuestLoadAll(); all.unshift({ name: name, filters: geGuestMakeFiltersPayload(), ts: Date.now() }); geGuestSaveAll(all); $("#ge-saved-container").html( '
' + esc(geGetUiText("search_saved_device", "Search saved on this device.")) + "
" ); return; } $("#ge-saved-container").html( '
' + esc(geGetUiText("save_search_failed", "Could not save search.")) + "
" ); }).fail(function () { $("#ge-saved-container").html( '
' + esc(geGetUiText("save_search_failed", "Could not save search.")) + "
" ); }); }); $(document) .off("click.geSavedSearch touchend.geSavedSearch", ".ge-saved-search") .on("click.geSavedSearch touchend.geSavedSearch", ".ge-saved-search", function (e) { e.preventDefault(); if (!geIsLoggedIn()) { const items = geGuestLoadAll().map(function (it) { return { name: it.name, filters: it.filters }; }); renderSavedSearches(items); return; } getSavedSearchesRequest() .done(function (res) { if (typeof res === "string") { try { res = JSON.parse(res); } catch (err) { res = {}; } } if (!res || !res.success || !Array.isArray(res.data)) { if (geServerSaysLoginRequired(res)) { const items = geGuestLoadAll().map(function (it) { return { name: it.name, filters: it.filters }; }); renderSavedSearches(items); return; } $("#ge-saved-container").html( '
' + esc(geGetUiText("no_saved_searches", "No saved searches.")) + "
" ); return; } renderSavedSearches(res.data); }) .fail(function () { $("#ge-saved-container").html( '
' + esc(geGetUiText("saved_searches_failed", "Could not load saved searches.")) + "
" ); }); }); $(document) .off("click.geRunSaved", ".ge-run-saved, .ge-saved-item") .on("click.geRunSaved", ".ge-run-saved, .ge-saved-item", function (e) { e.preventDefault(); const index = parseInt($(this).attr("data-index") || $(this).data("index"), 10); if (isNaN(index)) return; function runWithPayload(payload) { if (payload && typeof payload === "object") { if (payload.search && typeof payload.search === "object") payload = payload.search; if (payload.filters && typeof payload.filters === "object") payload = payload.filters; } applySearchPayload(payload || {}); state.nearbyMode = false; state.nearbyStage = 0; $(".ge-saved-list").remove(); runCombinedSearch(); } if (!geIsLoggedIn()) { const all = geGuestLoadAll(); const item = all[index]; if (!item || !item.filters) return; runWithPayload(item.filters); return; } $.post(geAjaxUrl(), { action: "ge_run_saved_search", index: index }).done(function (res) { if (!res || !res.success || !res.data || !res.data.filters) return; runWithPayload(res.data.filters); }); }); $(document).on("click", ".ge-saved-share", function (e) { e.preventDefault(); e.stopPropagation(); let payload = {}; try { payload = JSON.parse(String($(this).attr("data-payload") || "{}")); } catch (err) { payload = {}; } if (payload && typeof payload === "object") { if (payload.search && typeof payload.search === "object") payload = payload.search; if (payload.filters && typeof payload.filters === "object") payload = payload.filters; } geOpenShareMenu(this, geBuildShareUrl(payload), geGetUiText("share_search_title", "Check out this GloboEvent search")); }); $(document).on("click", ".ge-share-selected", function (e) { e.preventDefault(); const $selected = $(".ge-saved-radio:checked").first(); if (!$selected.length) { alert(geGetUiText("no_searches_selected", "No searches selected.")); return; } const index = parseInt($selected.val(), 10); const $row = $(`.ge-saved-item-row[data-index="${index}"]`); const $btn = $row.find(".ge-saved-item").first(); let payload = {}; try { payload = JSON.parse(String($btn.attr("data-payload") || "{}")); } catch (err) { payload = {}; } if (payload && typeof payload === "object") { if (payload.search && typeof payload.search === "object") payload = payload.search; if (payload.filters && typeof payload.filters === "object") payload = payload.filters; } geOpenShareMenu( this, geBuildShareUrl(payload), geGetUiText("share_selected_title", "Check out this GloboEvent saved search") ); }); $(document).on("click", ".ge-delete-selected", function (e) { e.preventDefault(); const $selected = $(".ge-saved-radio:checked").first(); if (!$selected.length) { alert(geGetUiText("no_searches_selected", "No searches selected.")); return; } const selected = [parseInt($selected.val(), 10)]; if (!geIsLoggedIn()) { const all = geGuestLoadAll(); const keep = all.filter(function (_, idx) { return selected.indexOf(idx) === -1; }); geGuestSaveAll(keep); $(`.ge-saved-item-row[data-index="${selected[0]}"]`).remove(); if (!$(".ge-saved-item-row").length) { $("#ge-saved-container").html( '
' + esc(geGetUiText("no_saved_searches", "No saved searches.")) + "
" ); } return; } $.ajax({ url: geAjaxUrl(), method: "POST", dataType: "json", timeout: 30000, data: { action: "ge_delete_saved_searches", indexes: selected } }).done(function (res) { if (res && res.success) { $(`.ge-saved-item-row[data-index="${selected[0]}"]`).remove(); if (!$(".ge-saved-item-row").length) { $("#ge-saved-container").html( '
' + esc(geGetUiText("no_saved_searches", "No saved searches.")) + "
" ); } } else { alert(geGetUiText("delete_failed", "Delete failed.")); } }).fail(function () { alert(geGetUiText("delete_failed", "Delete failed.")); }); }); $(document).on("click", ".ge-delete-all", function (e) { e.preventDefault(); if (!window.confirm(geGetUiText("delete_all_confirm", "Delete ALL saved searches?"))) return; if (!geIsLoggedIn()) { geGuestSaveAll([]); $("#ge-saved-container").html( '
' + esc(geGetUiText("no_saved_searches", "No saved searches.")) + "
" ); return; } $.ajax({ url: geAjaxUrl(), method: "POST", dataType: "json", timeout: 30000, data: { action: "ge_delete_all_saved_searches" } }).done(function (res) { if (res && res.success) { $("#ge-saved-container").html( '
' + esc(geGetUiText("no_saved_searches", "No saved searches.")) + "
" ); } else { alert(geGetUiText("delete_failed", "Delete failed.")); } }).fail(function () { alert(geGetUiText("delete_failed", "Delete failed.")); }); }); $(document).on("click", ".ge-cat-btn", function (e) { e.preventDefault(); const $btn = $(this); const alreadyActive = $btn.hasClass("active"); $(".ge-cat-btn").removeClass("active"); $(".ge-subcategory-group").attr("hidden", true); if (alreadyActive) { state.categoryId = 0; state.categorySlug = ""; state.subcategory = []; $(".ge-subcat-checkbox").prop("checked", false); return; } $btn.addClass("active"); state.categoryId = parseInt($btn.data("catId") || $btn.data("cat") || 0, 10) || 0; state.categorySlug = String($btn.data("catSlug") || "").trim(); if (state.categoryId) { $(`.ge-subcategory-group[data-parent="${state.categoryId}"]`).removeAttr("hidden"); $("#ge-category-modal").removeClass("hidden"); } }); $(document).on("click", "#ge-advanced-btn", function (e) { e.preventDefault(); $("#ge-advanced-panel").toggleClass("hidden"); }); $(document).on("click", "#ge-search-btn", function (e) { e.preventDefault(); state.nearbyMode = false; state.nearbyStage = 0; runCombinedSearch(); }); $(document).on("change", "#ge-keyword, #ge-city, #ge-country, #ge-zip", function () { state.nearbyMode = false; state.nearbyStage = 0; }); $(document).on("change", ".ge-subcat-checkbox", function () { state.nearbyMode = false; state.nearbyStage = 0; runCombinedSearch(); }); $(document).on("change", ".ge-audience-checkbox", function () { syncAudienceFromUi(); filterRenderedByAudience(); }); $(document).on("keydown", "#ge-keyword, #ge-city, #ge-country, #ge-zip", function (e) { if (e.key === "Enter") { e.preventDefault(); state.nearbyMode = false; state.nearbyStage = 0; runCombinedSearch(); } }); $(document).on("click", ".ge-today", function (e) { e.preventDefault(); setToday(); $("#ge-city").val(""); $("#ge-country").val(""); $("#ge-zip").val(""); state.nearbyMode = false; state.nearbyStage = 0; runCombinedSearch(); }); $(document).on("click", ".ge-weekend", function (e) { e.preventDefault(); setWeekend(); $("#ge-city").val(""); $("#ge-country").val(""); $("#ge-zip").val(""); state.nearbyMode = false; state.nearbyStage = 0; runCombinedSearch(); }); $(document).on("click", "#ge-reset-all", function (e) { e.preventDefault(); geResetSearchUi(); runCombinedSearch(); }); $(document).on("click", ".ge-load-more-btn", function (e) { e.preventDefault(); const type = String($(this).data("type") || ""); if (type !== "events" && type !== "activities") return; state.page[type] += 1; if (type === "events") { if (state.discovery.events.active) { renderNextDiscoveryEvents(); return; } $("#ge-event-pagination").html(loadMoreHtml("events", true)); eventsRequest(getScopedQuery(), state.page.events) .done(function (res) { const data = normalizeResponse(res); renderEventsSection(data, true); }) .fail(function (jqXHR, textStatus, errorThrown) { console.error("Load more events failed", { textStatus: textStatus, errorThrown: errorThrown, status: jqXHR && jqXHR.status, responseText: jqXHR && jqXHR.responseText }); state.page.events = Math.max(1, state.page.events - 1); $("#ge-event-pagination").html(loadMoreHtml("events", false)); alert(geGetUiText("events_failed_load_more", "Could not load more events. Please try again.")); }); return; } if (state.discovery.activities.active) { renderNextDiscoveryActivities(); return; } $("#ge-activity-pagination").html(loadMoreHtml("activities", true)); activitiesRequest(getScopedQuery(), state.page.activities) .done(function (res) { const data = normalizeResponse(res); renderActivitiesSection(data, true); }) .fail(function (jqXHR, textStatus, errorThrown) { console.error("Load more activities failed", { textStatus: textStatus, errorThrown: errorThrown, status: jqXHR && jqXHR.status, responseText: jqXHR && jqXHR.responseText }); state.page.activities = Math.max(1, state.page.activities - 1); $("#ge-activity-pagination").html(loadMoreHtml("activities", false)); alert(geGetUiText("activities_failed_load_more", "Could not load more activities. Please try again.")); }); }); const langSelectEl = document.querySelector("#ge-language-select, .ge-language-select"); if (langSelectEl) { langSelectEl.addEventListener("change", function (e) { e.stopImmediatePropagation(); e.stopPropagation(); const chosen = geNormalizeLang(e.target.value); $.post(geAjaxUrl(), { action: "ge_set_language", lang: chosen }) .done(function (res) { let confirmed = chosen; if (res && res.success && res.data && res.data.lang) { confirmed = geNormalizeLang(res.data.lang); } geSetLangRuntime(confirmed); if (res && res.success && res.data) { if (res.data.ui) geApplyUiDict(res.data.ui); else if (res.data.dict && res.data.dict.ui) geApplyUiDict(res.data.dict.ui); if (res.data.audience) geApplyAudienceDict(res.data.audience); else if (res.data.dict && res.data.dict.audience) geApplyAudienceDict(res.data.dict.audience); applyUiLabels(); return; } geLoadUiDict(confirmed, function () { applyUiLabels(); }); }) .fail(function () { geSetLangRuntime(chosen); geLoadUiDict(chosen, function () { applyUiLabels(); }); }); }, true); } $(document).on("click", ".ge-event-card a", function () { const $card = $(this).closest(".ge-event-card"); geSaveCombinedResultsState({ id: String($card.attr("data-id") || $card.data("id") || "").trim(), url: String($(this).attr("href") || $card.attr("data-url") || $card.data("url") || "").trim() }); }); function setupMobileAdvancedActions() { if (window.innerWidth > 768) return; const $panel = $("#ge-advanced-panel"); if (!$panel.length) return; let $actions = $panel.find(".ge-advanced-actions"); if (!$actions.length) { $panel.prepend('
'); $actions = $panel.find(".ge-advanced-actions"); } const $save = $(".ge-filter-row .ge-save-search").first(); const $saved = $(".ge-filter-row .ge-saved-search").first(); if ($save.length && !$actions.find(".ge-save-search").length) { $actions.append($save.clone(true, true).css("display", "")); } if ($saved.length && !$actions.find(".ge-saved-search").length) { $actions.append($saved.clone(true, true).css("display", "")); } } setupMobileAdvancedActions(); bindNearby(); bindTabs(); initDatePicker(); geEnsureSavedContainer(); const initialLang = geEnsureLanguage(); const isBack = geIsBackIntent(); let isReload = false; try { const nav = performance.getEntriesByType("navigation"); if (nav && nav[0] && nav[0].type === "reload") { isReload = true; sessionStorage.removeItem(GE_SS_KEYS.combined); geResetSearchUi(); } } catch (e) {} if (!isReload && isBack && geRestoreCombinedResultsState()) { geLoadUiDict(initialLang, function () { applyUiLabels(); geApplyResultButtonsToDom(); }); return; } geLoadUiDict(initialLang, function () { applyUiLabels(); runCombinedSearch(); }); });